package com.hanxiaozhang.handler;


import com.hanxiaozhang.annotation.EnableGlobalException;
import com.hanxiaozhang.exception.BusinessException;
import com.hanxiaozhang.exception.ParameterNotValidException;
import com.hanxiaozhang.result.ResultCode;
import com.hanxiaozhang.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.List;

/**
 * 功能描述: <br>
 * 〈全局异常处理类〉
 *  需要通过注解在Controller上打注解启动{@link EnableGlobalException}
 *
 * @Author:hanxiaozhang
 * @Date: 2020/7/21
 */
@Slf4j
@RestController
@ControllerAdvice(annotations = EnableGlobalException.class)
public class GlobalExceptionHandler{

	/**
	 * 处理违反约束异常
	 *
	 * @param e
	 * @param request
	 * @return
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(ConstraintViolationException.class)
	public Result handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
		log.info("handleConstraintViolationException start, uri:[{}], caused by:", request.getRequestURI(), e);
		List<String> invalidParameterList = HandleInvalidParameter.convertConstraintViolationToInvalidParameterList(e.getConstraintViolations(),true);
		return Result.error(ResultCode.PARAM_IS_INVALID, e, HttpStatus.BAD_REQUEST, invalidParameterList);

	}

	/**
	 * 处理验证参数封装错误异常
	 *
	 * @param e
	 * @param request
	 * @return
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(HttpMessageNotReadableException.class)
	public Result handleConstraintViolationException(HttpMessageNotReadableException e, HttpServletRequest request) {
		log.info("handleConstraintViolationException start, uri:[{}], caused by:", request.getRequestURI(), e);
		return Result.error(ResultCode.PARAM_IS_INVALID, e, HttpStatus.BAD_REQUEST);
	}

	/**
	 * 处理参数绑定异常
	 *
	 * @param e
	 * @param request
	 * @return
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(BindException.class)
	public Result handleBindException(BindException e, HttpServletRequest request) {
		log.info("handleBindException start, uri:[{}], caused by:", request.getRequestURI(), e);
		List<String> invalidParameterList = HandleInvalidParameter.convertBindingResultToInvalidParameterList(e.getBindingResult(),true);
		return Result.error(ResultCode.PARAM_IS_INVALID, e, HttpStatus.BAD_REQUEST, invalidParameterList);
	}

	/**
	 * 处理@Validated注解参数验证错误异常
	 *
	 * @param e
	 * @param request
	 * @return
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
		log.info("handleMethodArgumentNotValidException start, uri:[{}], caused by:", request.getRequestURI(), e);
		List<String> invalidParameterList = HandleInvalidParameter.convertBindingResultToInvalidParameterList(e.getBindingResult(),true);
		return Result.error(ResultCode.PARAM_IS_INVALID, e, HttpStatus.BAD_REQUEST, invalidParameterList);
	}


	/**
	 * 处理ValidationUtil.checkParameter()参数验证错误异常
	 *
	 * @param e
	 * @param request
	 * @return
	 */
	@ExceptionHandler(ParameterNotValidException.class)
	public Result handleParameterNotValidException(ParameterNotValidException e, HttpServletRequest request) {
		log.info("handleParameterNotValidException start, uri:[{}], caused by:", request.getRequestURI(), e);
		return Result.error(ResultCode.PARAM_IS_INVALID, e, HttpStatus.BAD_REQUEST, e.getMessage());
	}


	/**
	 * 处理自定义异常
	 *
	 * @param e
	 * @param request
	 * @return
	 */
	@ExceptionHandler(BusinessException.class)
	public Result handleBusinessException(BusinessException e, HttpServletRequest request) {
		log.info("handleBusinessException start, uri:[{}], exception:[{}], caused by:", request.getRequestURI(), e.getClass(), e.getMessage());
		return Result.error(e);
	}

	/**
	 * 处理运行时异常
	 *
	 * @param e
	 * @param request
	 * @return
	 */
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(Throwable.class)
	public Result handleThrowable(Throwable e, HttpServletRequest request) {
		log.error("handleThrowable start, uri:[{}], caused by:", request.getRequestURI(), e);
		return Result.error(ResultCode.SYSTEM_INNER_ERROR, e, HttpStatus.INTERNAL_SERVER_ERROR);
	}


}
